﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace HA.MT3DMS.FileLayer
{
    /// <summary>
    /// 基本运移子程序包
    /// </summary>
    public class BasicTransportPack : Package
    {
        public BasicTransportPack()
        {
            this._fileType = FileType.BTN;
            this.Fname = "mt3dms.btn";
        }

        private int _NLAY;
        /// <summary>
        /// 是总层数；应是和modflow相同，界面中并不表现，直接承接网格设置
        /// </summary>
        public int NLAY
        {
            get { return _NLAY; }
            set { _NLAY = value; }
        }
        private int _NROW;
        /// <summary>
        /// 是总行数；应是和modflow相同，界面中并不表现，直接承接网格设置
        /// </summary>
        public int NROW
        {
            get { return _NROW; }
            set { _NROW = value; }
        }
        private int _NCOL;
        /// <summary>
        /// 是总列数；应是和modflow相同，界面中并不表现，直接承接网格设置
        /// </summary>
        public int NCOL
        {
            get { return _NCOL; }
            set { _NCOL = value; }
        }
        private int _NPER;
        /// <summary>
        /// 是应力期的数量；界面中不表现，由用户设置的应力期获得此数值
        /// </summary>
        public int NPER
        {
            get { return _NPER; }
            set { _NPER = value; }
        }
        private int _NCOMP;
        /// <summary>
        /// 是当前模拟包含的化学物种的数量。对于单物种模拟，NCOMP=1；界面中不表现，由用户设置的化学物种获得此数值
        /// </summary>
        public int NCOMP
        {
            get { return _NCOMP; }
            set { _NCOMP = value; }
        }
        private int _MCOMP;
        /// <summary>
        /// 界面中不表现，由用户设置的化学物种获得此数值
        /// 是“活动”物种的总数量。MCOMP必须小于等于NCOMP。
        /// 单物种模拟时，MCOMP=1。界面中不表现，由用户设置的活动”化学物种获得此数值
        /// </summary>
        public int MCOMP
        {
            get { return _MCOMP; }
            set { _MCOMP = value; }
        }
        private string _TUNIT;
        /// <summary>
        /// 是时间单位的名称，例如天（DAY）或小时（HOUR）；
        /// </summary>
        public string TUNIT
        {
            get { return _TUNIT; }
            set { _TUNIT = value; }
        }
        private string _LUNIT;
        /// <summary>
        /// 是长度单位的名称，例如英尺（FT）或米（M）
        /// </summary>
        public string LUNIT
        {
            get { return _LUNIT; }
            set { _LUNIT = value; }
        }
        private string _MUNIT;

        /// <summary>
        /// 是重量单位的名称，例如磅（LB）或千克（KG）；注意，这些名称只作识别之用，并不会影响模拟结果
        /// </summary>
        public string MUNIT
        {
            get { return _MUNIT; }
            set { _MUNIT = value; }
        }

        private string _ADV = "F";
        /// <summary>
        /// 水平对流（Advection）
        /// </summary>
        public string ADV
        {
            get { return _ADV; }
            set { _ADV = value; }
        }

        private string _DSP = "F";
        /// <summary>
        /// 弥散（Dispersion）
        /// </summary>
        public string DSP
        {
            get { return _DSP; }
            set { _DSP = value; }
        }
        private string _SSM = "F";
        /// <summary>
        /// 源汇混合（Sink & Source Mixing）
        /// </summary>
        public string SSM
        {
            get { return _SSM; }
            set { _SSM = value; }
        }
        private string _RCT = "F";
        /// <summary>
        /// 化学反应（Chemical Reaction）
        /// </summary>
        public string RCT
        {
            get { return _RCT; }
            set { _RCT = value; }
        }
        private string _GCG = "T";
        /// <summary>
        /// 广义共轭梯度求解（Generalized Conjugate Gradient Solver）子程序包
        /// </summary>
        public string GCG
        {
            get { return _GCG; }
            set { _GCG = value; }
        }


        private List<int> _LAYCON = new List<int>();
        /// <summary>
        /// 层类型
        /// </summary>
        public List<int> LAYCON
        {
            get { return _LAYCON; }
            set { _LAYCON = value; }
        }

        private List<double> _DELR = new List<double>();
        /// <summary>
        /// 网格行间距
        /// </summary>
        public List<double> DELR
        {
            get { return _DELR; }
            set { _DELR = value; }
        }
        private List<double> _DELC = new List<double>();
        /// <summary>
        /// 网格列间距
        /// </summary>
        public List<double> DELC
        {
            get { return _DELC; }
            set { _DELC = value; }
        }

        private double[,] _HTOP;
        /// <summary>
        /// 模型顶层高程
        /// 一个二维数组，定义第一模型层（顶层）的所有单元，其基准面与水头的基准面相同
        /// </summary>
        public double[,] HTOP
        {
            get { return _HTOP; }
            set { _HTOP = value; }
        }
        protected List<double[,]> _DZ = new List<double[,]>();
        /// <summary>
        /// 网格中每一层有一个数组
        /// 每个模层的所有单元的厚度
        /// 界面没有表现，其数值由modflow的设置给出，需要自己计算
        /// </summary>
        public List<double[,]> DZ
        {
            get { return _DZ; }
            set { _DZ = value; }
        }

        private List<double[,]> _PRSITY = new List<double[,]>();
        /// <summary>
        /// 每一层有一个数组
        /// 有效孔隙度
        /// 是单孔隙系统中多孔介质的“有效”孔隙度
        /// </summary>
        public List<double[,]> PRSITY
        {
            get { return _PRSITY; }
            set { _PRSITY = value; }
        }
        private List<int[,]> _ICBUND = new List<int[,]>();
        /// <summary>
        /// 每一层有一个数组
        /// 边界
        /// 是一个指定每个模型单元边界条件种类（无效，恒定浓度，或活动）的整数数组。
        /// </summary>
        public List<int[,]> ICBUND
        {
            get { return _ICBUND; }
            set { _ICBUND = value; }
        }

        private List<double[,]> _SCONC = new List<double[,]>();
        /// <summary>
        /// 污染物的初始浓度
        /// 每一层有一个数组
        /// 是模拟开始的初始浓度（单位为ML-3）。对于多物种模拟，初始浓度必须为每个物种指定，一次一个物种
        /// </summary>
        public List<double[,]> SCONC
        {
            get { return _SCONC; }
            set { _SCONC = value; }
        }

        private double _CINACT;
        /// <summary>
        /// 标示【无效浓度单元】的数值（ICBUND=0）。
        /// 必须提交一个CINACT值，甚至当无效单元并不参与模型的时候
        /// </summary>
        public double CINACT
        {
            get { return _CINACT; }
            set { _CINACT = value; }
        }
        private double _THKMIN;
        /// <summary>
        /// 是一个单元的【最小饱和浓度】，表示低于模型厚度的此小数倍时单元被认为无效。
        /// 默认值为0.01（即模型厚度的百分之一）
        /// </summary>
        public double THKMIN
        {
            get { return _THKMIN; }
            set { _THKMIN = value; }
        }
        private int _IFMTCN;
        /// <summary>
        /// 标示是否将计算的浓度列印入标准输入文字文件，同时如果列印它也作为列印格式编码使用
        /// >0，浓度以wrap格式被列印（图29）。
        ///  小于0，浓度以strip格式被列印（图29）。
        /// =0，浓度不被列印
        /// </summary>
        public int IFMTCN
        {
            get { return _IFMTCN; }
            set { _IFMTCN = value; }
        }
        private int _IFMTNP;
        /// <summary>
        /// IFMTNP标示是否将每个单元中颗粒数量（整数）列印，
        /// 同时如果列印它也作为列印格式编码使用。它同IFMTCN的惯例一样
        /// </summary>
        public int IFMTNP
        {
            get { return _IFMTNP; }
            set { _IFMTNP = value; }
        }
        private int _IFMTRF;
        /// <summary>
        /// 标示是否将模型计算中的阻滞因数列印，
        /// 同时如果列印它也作为列印格式编码使用。它同IFMTCN的惯例一样
        /// </summary>
        public int IFMTRF
        {
            get { return _IFMTRF; }
            set { _IFMTRF = value; }
        }
        private int _IFMTDP;
        /// <summary>
        /// 标示是否将模型计算中的距离加权离散系数列印，
        /// 同时如果列印它也作为列印格式编码使用。它同IFMTCN的惯例一样
        /// </summary>
        public int IFMTDP
        {
            get { return _IFMTDP; }
            set { _IFMTDP = value; }
        }
        private string _SAVUCN;
        /// <summary>
        /// 是一个逻辑标识，
        /// 表示是否为了后处理或在后续的运行中作为初始条件使用将浓度解
        /// 保存在默认的未格式化（二进制）文件MT3Dnnn.UCN中，其中nnn是物种索引号。
        /// 当SAVUCN=T，每个物种的浓度将被保存在默认的MT3Dnnn.UCN中。
        /// 另外模型的空间离散信息将被保存在另一个默认文件MT3D.CNF中同MT3Dnnn.UCN一起为后处理使用。
        /// 当SAVUCN=F，MT3Dnnn.UCN和MT3D.CNF都不会被创建。
        /// </summary>
        public string SAVUCN
        {
            get { return _SAVUCN; }
            set { _SAVUCN = value; }
        }
        private int _NPRS;
        /// <summary>
        /// 标示输出频率以及输出频率是以模拟总时长还是以运移阶号来定义的
        /// >0，模拟结果将被列印入标准输出文字文件或保存至未格式化的浓度文件，
        /// 次数以下一个纪录中输入的TIMPRS（NPRS）纪录指定。
        /// =0，模拟结果除了模拟结束时不会被列印或保存
        /// 小于0，模拟结果每当运移阶数是NPRS的偶数倍时将被列印或保存。
        /// </summary>
        public int NPRS
        {
            get { return _NPRS; }
            set { _NPRS = value; }
        }
        private List<double> _TIMPRS = new List<double>();
        /// <summary>
        ///  当选择第一个选项时，即当NPRS>0时，输入
        /// 是当模拟结果被列印入标准输出文字文件或被保存至默认的未格式化（二进制）
        /// 浓度文件MT3Dnnn.UCN时的总经时长
        /// </summary>
        public List<double> TIMPRS
        {
            get { return _TIMPRS; }
            set { _TIMPRS = value; }
        }


        private int _NOBS;
        /// <summary>
        /// 是观测点的数量
        /// </summary>
        public int NOBS
        {
            get { return _NOBS; }
            set { _NOBS = value; }
        }
        private int _NPROBS;
        /// <summary>
        /// 是一个整数，标示指定观测点上的浓度被保存在观测文件MT3Dnnn.OBS的频率。
        /// 每个NPROBS阶段会保存浓度一次
        /// </summary>
        public int NPROBS
        {
            get { return _NPROBS; }
            set { _NPROBS = value; }
        }


        #region 层行列
        //private int _KOBS;
        ///// <summary>
        ///// 单元索引号,层
        ///// 如果NOBS>0，被输入NOBS次
        ///// </summary>
        //public int KOBS
        //{
        //    get { return _KOBS; }
        //    set { _KOBS = value; }
        //}
        //private int _IOBS;
        ///// <summary>
        ///// 单元索引号,行
        ///// 如果NOBS>0，被输入NOBS次
        ///// </summary>
        //public int IOBS
        //{
        //    get { return _IOBS; }
        //    set { _IOBS = value; }
        //}
        //private int _JOBS;
        ///// <summary>
        ///// 单元索引号,列
        /////  如果NOBS>0，被输入NOBS次
        ///// </summary>
        //public int JOBS
        //{
        //    get { return _JOBS; }
        //    set { _JOBS = value; }
        //}
        #endregion

        private List<double[]> _KIJOBS = new List<double[]>();
        /// <summary>
        /// 单元索引号,层，行，列
        /// 如果NOBS>0，被输入NOBS次
        /// </summary>
        public List<double[]> KIJOBS
        {
            get { return _KIJOBS; }
            set { _KIJOBS = value; }
        }
        private string _CHKMAS;
        /// <summary>
        /// 标示一行质量均衡信息摘要是否应为了检查和后处理的目的被列印入
        /// 默认文件MT3Dnnn.MAS的逻辑标识，其中nnn是物种的索引号。
        /// 如果CHKMAS=T, 每个运移阶段的质量均衡信息将被保存在MT3Dnnn.MAS文件中
        /// 如果CHKMAS=F，MT3Dnnn.MAS文件将不会被创建
        /// </summary>
        public string CHKMAS
        {
            get { return _CHKMAS; }
            set { _CHKMAS = value; }
        }
        private int _NPRMAS;
        /// <summary>
        /// 标示质量预算信息应被保存在质量均衡摘要文件MT3Dnnn.MAS的频率。
        /// 每个NPRMAS阶段会保存质量预算信息一次
        /// </summary>
        public int NPRMAS
        {
            get { return _NPRMAS; }
            set { _NPRMAS = value; }
        }




        List<FStressPeriod> _periods = new List<FStressPeriod>();

        public List<FStressPeriod> Periods
        {
            get { return _periods; }
            set { _periods = value; }
        }

       


        public override void WriteFile(string path)
        {
            string content = "HuanAn MT3D simulation" + "\r\n";
            content += System.DateTime.Now.ToLongDateString() + "\r\n";
            content += string.Format("{0,10}", GetNumberLengthFormat(this.NLAY, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.NROW, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.NCOL, 10)) +
                     string.Format("{0,10}", GetNumberLengthFormat(this.NPER, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.NCOMP, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.MCOMP, 10)) + "  !NLAY,NROW,NCOL,NPER,NCOMP,MCOMP" + "\r\n";
            content += string.Format("{0,4}", GetNumberLengthFormat(this.TUNIT, 4)) + string.Format("{0,4}", GetNumberLengthFormat(this.LUNIT, 4)) + string.Format("{0,4}", GetNumberLengthFormat(this.MUNIT, 4)) + "                                                  !TUNIT,LUNIT,MUNIT" + "\r\n";
            content += string.Format("{0,2}", this.ADV) + string.Format("{0,2}", this.DSP) + string.Format("{0,2}", this.SSM) +
                       string.Format("{0,2}", GetNumberLengthFormat(this.RCT, 2)) + string.Format("{0,2}", GetNumberLengthFormat(this.GCG, 2)) + " F F F F F" + "                            !TRNOP: ADV,DSP,SSM,RCT,GCG..." + "\r\n";
            string str = "";
            for (int i = 0; i < this.LAYCON.Count; i++)
            {
                str += string.Format("{0,2}", GetNumberLengthFormat(this.LAYCON[i], 2));
            }
            content += str + "                                              !LAYCON" + "\r\n";
            if (IsConstant(this.DELR))
            {
                content += string.Format("{0,10}", GetNumberLengthFormat(0, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.DELR[0], 10)) + "                                          !DELR" + "\r\n";
            }
            else
            {
                GetArrayString(this.DELR, ref  str);                
                content += str;
            }

            if (IsConstant(this.DELC))
            {
                content += string.Format("{0,10}", GetNumberLengthFormat(0, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.DELC[0], 10)) + "                                          !DELC" + "\r\n";
            }
            else
            {
                GetArrayString(this.DELC, ref  str);             
                content += str;
            }


            if (IsConstant(this.HTOP))
            {
                content += string.Format("{0,10}", GetNumberLengthFormat(0, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.HTOP[0, 0], 10)) + "                                          !HTOP" + "\r\n";
            }
            else
            {
                GetArrayString(this.HTOP, ref  str);
            
                content += str;
            }


            str = "";
            string str1 = "";
            for (int i = 0; i < this.DZ.Count; i++)
            {
                if (IsConstant(this.DZ[i]))
                {
                    str += string.Format("{0,10}", GetNumberLengthFormat(0, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.DZ[i][0, 0], 10)) + "                                          !DZ-LAYER " + (i + 1).ToString() + "\r\n";
                }
                else
                {
                    GetArrayString(this.DZ[i], ref  str1);
                   
                    str += str1;
                }

            }
            content += str;

            str = "";
            str1 = "";
            for (int i = 0; i < this.PRSITY.Count; i++)
            {
                if (IsConstant(this.PRSITY[i]))
                {
                    str += string.Format("{0,10}", GetNumberLengthFormat(0, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.PRSITY[i][0, 0], 10)) + "                                          !PRSITY-LAYER " + (i + 1).ToString() + "\r\n";
                }
                else
                {
                    GetArrayString(this.PRSITY[i], ref  str1);
                   
                    str += str1;
                }

            }
            content += str;

            str = "";
            str1 = "";
            for (int i = 0; i < this.ICBUND.Count; i++)
            {
                if (IsConstant(this.ICBUND[i]))
                {
                    str += string.Format("{0,10}", GetNumberLengthFormat(0, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.ICBUND[i][0, 0], 10)) + "                                          !ICBUND-LAYER " + (i + 1).ToString() + "\r\n";
                }
                else
                {
                    GetArrayString(this.ICBUND[i], ref  str1);
                   
                    str += str1;
                }

            }
            content += str;

            str = "";
            str1 = "";
            for (int i = 0; i < this.SCONC.Count; i++)
            {
                if (IsConstant(this.SCONC[i]))
                {
                    str += string.Format("{0,10}", GetNumberLengthFormat(0, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.SCONC[i][0, 0], 10)) + "                                          !SCONC-LAYER " + (i + 1).ToString() + "\r\n";
                }
                else
                {
                    GetArrayString(this.SCONC[i], ref  str1);
                   
                    str += str1;
                }

            }
            content += str;

            content += string.Format("{0,10}", GetNumberLengthFormat(this.CINACT, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.THKMIN, 10)) + "                                          !CINACT,THKMIN" + "\r\n";
            content += string.Format("{0,10}", GetNumberLengthFormat(this.IFMTCN, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.IFMTNP, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.IFMTRF, 10)) +
                       string.Format("{0,10}", GetNumberLengthFormat(this.IFMTDP, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.SAVUCN, 10)) + "            !IFMTCN, IFMTNP, IFMTRF, IFMTDP, SAVUCN" + "\r\n";

            content += string.Format("{0,10}", GetNumberLengthFormat(this.NPRS, 10)) + "                                                    !NPRS" + "\r\n";
            if (this.NPRS > 0)
            {
                int p = 1;
                for (int i = 0; i < this.TIMPRS.Count; i++)
                {
                    if (p >= 8)
                    {
                        content += string.Format("{0,10}", GetNumberLengthFormat(this.TIMPRS[i], 10)) + "\r\n";
                        p = 0;
                    }
                    else
                    {
                        content += string.Format("{0,10}", GetNumberLengthFormat(this.TIMPRS[i], 10));
                    }
                    p++;
                }
                if (this.TIMPRS.Count % 8 == 0)
                {

                }
                else
                {
                    content += "  !TIMPRS" + "\r\n";
                }

            }
            content += string.Format("{0,10}", GetNumberLengthFormat(this.NOBS, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.NPROBS, 10)) + "                                          !NOBS,NPROBS" + "\r\n";
            //content += string.Format("{0,10}", this.KOBS) + string.Format("{0,10}", this.IOBS) + string.Format("{0,10}", this.JOBS) + "                                !KOBS,IOBS,JOBS" + "\r\n";
            if (this.NOBS > 0)
            {
                for (int i = 0; i < this._KIJOBS.Count; i++)
                {
                    for (int j = 0; j < this._KIJOBS[i].Length; j++)
                    {
                        content += string.Format("{0,10}", GetNumberLengthFormat(this._KIJOBS[i][j], 10)) + "\r\n";
                    }
                }
                content += "                                !KOBS,IOBS,JOBS" + "\r\n";
            }

            content += string.Format("{0,10}", GetNumberLengthFormat(this.CHKMAS, 10)) + string.Format("{0,10}", GetNumberLengthFormat(this.NPRMAS, 10)) + "                                          !CHKMAS,NPRMAS" + "\r\n";


            foreach (FStressPeriod sp in this.Periods)
            {
                //if (sp.NSTP > 1)
                //{
                    content += string.Format("{0,10}", GetNumberLengthFormat(sp.PERLEN, 10)) + string.Format("{0,10}", GetNumberLengthFormat(sp.NSTP, 10)) + string.Format("{0,10}", GetNumberLengthFormat(sp.TSMULT, 10)) + "                                !PERLEN,NSTP,TSMULT" + "\r\n";
                //}
                //else
                //{
                //    content += string.Format("{0,10}", GetNumberLengthFormat(sp.PERLEN, 10)) + string.Format("{0,10}", GetNumberLengthFormat(sp.NSTP, 10)) + "                                !PERLEN,NSTP" + "\r\n";
                //}
                if (sp.TSMULT <= 0)
                {
                    for (int i = 0; i < sp.TSLNGH.Count; i++)
                    {

                        content += string.Format("{0,10}", GetNumberLengthFormat(sp.TSLNGH[i], 10));
                    }
                    content += "  !TSLNGH" + "\r\n";
                }

                content += string.Format("{0,10}", GetNumberLengthFormat(sp.DT0, 10)) + string.Format("{0,10}", GetNumberLengthFormat(sp.MXSTRN, 10)) + string.Format("{0,10}", GetNumberLengthFormat(sp.TTSMULT, 10)) +
                           string.Format("{0,10}", GetNumberLengthFormat(sp.TTSMAX, 10)) + "                      !DT0,MXSTRN,TTSMULT,TTSMAX" + "\r\n";

            }

            string fname = path + this.Fname;
            HAUtil.FileOperations.WriteFile(fname, content);

        }
    }
}
